package com.app.couponsharelife.ui.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.*
import android.widget.OverScroller
import androidx.core.content.ContextCompat
import com.app.couponsharelife.R
import com.app.couponsharelife.utils.AppUtils

/**
 * Created by guluwa on 2018/12/2.
 */
class WheelView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
        View(context, attrs, defStyleAttr) {
    /**
     * 分割线画笔
     */
    private lateinit var mIndicatorPaint: Paint

    /**
     * 选中文字画笔
     */
    private lateinit var mSelectTextPaint: Paint

    /**
     * 普通文字画笔
     */
    private lateinit var mNormalTextPaint: Paint

    /**
     * view宽度
     */
    private var mViewWidth = 0

    /**
     * view高度
     */
    private var mViewHeight = 0
    /**
     * 控制滑动
     */
    private var mOverScroller: OverScroller? = null

    /**
     * 速度获取
     */
    private var mVelocityTracker: VelocityTracker? = null

    /**
     * 惯性最大速度
     */
    private var mMaximumVelocity: Int = 0

    /**
     * 惯性最小速度
     */
    private var mMinimumVelocity: Int = 0

    /**
     * 最小（上）位置
     */
    private var mMinPosition = 0

    /**
     * 最大（下）位置
     */
    private var mMaxPosition = 0

    /**
     * 条目高度
     */
    private var mItemHeight = 0

    /**
     * 选中文字Y偏移
     */
    private var mSelectTextYPositionOffset = 0f

    /**
     * 普通文字Y偏移
     */
    private var mNormalTextYPositionOffset = 0f

    /**
     * 数据列表
     */
    var list = mutableListOf<String>()
        set(value) {
            field = value
            invalidate()
        }

    /**
     * 选中位置
     */
    var mSelectPosition = 0

    var listener: com.app.couponsharelife.ui.listener.OnClickListener? = null

    init {
        initPaint()
        initOverScroll()
    }

    private fun initPaint() {
        mIndicatorPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mIndicatorPaint.color = ContextCompat.getColor(context, R.color.act_bg_color)
        mIndicatorPaint.strokeWidth = AppUtils.dip2px(context, 1f).toFloat()

        mSelectTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mSelectTextPaint.color = ContextCompat.getColor(context, R.color.black)
        mSelectTextPaint.textSize = AppUtils.sp2px(context, 17f).toFloat()

        mNormalTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mNormalTextPaint.color = ContextCompat.getColor(context, R.color.black)
        mNormalTextPaint.textSize = AppUtils.sp2px(context, 16f).toFloat()

        mItemHeight = AppUtils.dip2px(context, 42f)
    }

    /**
     * OverScroll初始化
     */
    private fun initOverScroll() {
        mOverScroller = OverScroller(context)
        mVelocityTracker = VelocityTracker.obtain()
        mMaximumVelocity = ViewConfiguration.get(context).scaledMaximumFlingVelocity
        mMinimumVelocity = ViewConfiguration.get(context).scaledMinimumFlingVelocity
    }

    /**
     * 设置起始刻度
     */
    private fun initCurrentScale() {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                scrollTo(0, scaleToScrollY())
            }
        })
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        initTextYPosition()
        mViewWidth = AppUtils.getDisplayMetrics(context).widthPixels
        mViewHeight = mItemHeight * list.size
        setMeasuredDimension(mViewWidth, mViewHeight)
        initCurrentScale()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        mMinPosition = mItemHeight * -2
        mMaxPosition = mItemHeight * (list.size - 3)
    }

    private fun initTextYPosition() {
        //计算刻度文字Y坐标
        val fontMetrics1 = mSelectTextPaint.fontMetrics
        mSelectTextYPositionOffset = paddingTop + (mItemHeight.toFloat() - fontMetrics1.top - fontMetrics1.bottom) / 2

        //计算单位文字Y坐标
        val fontMetrics2 = mNormalTextPaint.fontMetrics
        mNormalTextYPositionOffset = paddingTop + (mItemHeight.toFloat() - fontMetrics2.top - fontMetrics2.bottom) / 2
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        for (i in 0 until list.size) {
            val item = list[i]
            if (i != mSelectPosition) {
                canvas?.drawText(item, (mViewWidth - mNormalTextPaint.measureText(item)) / 2,
                        mNormalTextYPositionOffset + mItemHeight * i, mNormalTextPaint)
            } else {
                canvas?.drawText(item, (mViewWidth - mSelectTextPaint.measureText(item)) / 2,
                        mSelectTextYPositionOffset + mItemHeight * i, mSelectTextPaint)
            }
        }
    }

    private var mMoveStartY = 0f

    /**
     * 触摸事件
     */
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        val currentY = event!!.y
        //开始速度检测
        if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain()
        mVelocityTracker?.addMovement(event)

        if (mOverScroller == null) mOverScroller = OverScroller(context)

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (!mOverScroller!!.isFinished) {
                    mOverScroller?.abortAnimation()
                }
                mMoveStartY = currentY
            }
            MotionEvent.ACTION_MOVE -> {
                scrollBy(0, (mMoveStartY - currentY).toInt())
                mMoveStartY = currentY
            }
            MotionEvent.ACTION_UP -> {
                mVelocityTracker?.computeCurrentVelocity(1000, mMaximumVelocity.toFloat())
                val yVelocity = mVelocityTracker!!.yVelocity
                if (Math.abs(yVelocity) > mMinimumVelocity) {//滑动
                    fling(-yVelocity.toInt())
                } else {//返回最近刻度
                    scrollMoreNearScale()
                }
                releaseVelocityTracker()
            }
            MotionEvent.ACTION_CANCEL -> {
                if (!mOverScroller!!.isFinished) {
                    mOverScroller?.abortAnimation()
                }
                scrollMoreNearScale()
                releaseVelocityTracker()
            }
        }
        return true
    }

    /**
     * 惯性滑动
     */
    private fun fling(vY: Int) {
        mOverScroller?.fling(0, scrollY, 0, vY, 0, 0, mMinPosition, mMaxPosition)
        postInvalidate()
    }

    override fun computeScroll() {
        // 先推断mScroller滚动是否完毕
        if (mOverScroller != null && mOverScroller!!.computeScrollOffset()) {
            // 这里调用View的scrollTo()完毕实际的滚动
            scrollTo(mOverScroller!!.currX, mOverScroller!!.currY)
            if (!mOverScroller!!.computeScrollOffset()) {
                scrollMoreNearScale()
            }
            // 必须调用该方法，否则不一定能看到滚动效果
            postInvalidate()
        }
    }

    /**
     * 滚动完成后 回弹到最近的刻度
     */
    private fun scrollMoreNearScale() {
        //渐变回弹
        mOverScroller?.startScroll(0, scrollY, 0, scaleToScrollY() - scrollY, 500)
        postInvalidate()
        //立刻回弹
//        scrollTo(scaleToScrollY(), 0)
    }

    /**
     * VelocityTracker回收
     */
    private fun releaseVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker?.recycle()
            mVelocityTracker = null
        }
    }

    /**
     * 重写滑动
     * 小于最小刻度 不能滑动 出现左边缘效果
     * 大于最大刻度 不能滑动 出现右边缘效果
     * 滑动结束 通知result显示
     */
    override fun scrollTo(x: Int, y: Int) {
        val temp =
                when {
                    y < mMinPosition -> {
                        mMinPosition
                    }
                    y > mMaxPosition -> {
                        mMaxPosition
                    }
                    else -> y
                }
        if (temp != scrollY)
            super.scrollTo(x, temp)
        mSelectPosition = scrollYToScale()
        listener?.click(0, mSelectPosition)
    }

    /**
     * 滑动偏移距离转刻度
     */
    private fun scrollYToScale(): Int {
        return (scrollY - mMinPosition) / mItemHeight
    }

    /**
     * 刻度转滑动距离
     */
    private fun scaleToScrollY(): Int {
        return mSelectPosition * mItemHeight + mMinPosition
    }
}